﻿Imports System.Web
Imports System.Linq

Public Class UsersRolesMatrixHttpHandler
  Implements IHttpHandler

  Public ReadOnly Property IsReusable() As Boolean Implements System.Web.IHttpHandler.IsReusable
    Get
      Return True
    End Get
  End Property

  Public Sub ProcessRequest(ByVal context As System.Web.HttpContext) Implements System.Web.IHttpHandler.ProcessRequest
    If ProcessAddRemoveActions(context.Request.QueryString) Then
      Call context.Response.Write("OK")
    Else
      Dim strRoles = Security.Roles.GetAllRoles
      Dim strUsers = GetUsers(context)
      Dim strTableHtml As String = GetTableHtml(strRoles, strUsers)

      Dim strTemplate As String = My.Resources.UsersRolesMatrixTemplate

      strTemplate = strTemplate.Replace("EXECUTINGPATH", context.Request.CurrentExecutionFilePath.TrimStart("/"c))
      strTemplate = strTemplate.Replace("<!-- TABLE INSERTED HERE! -->", strTableHtml)
      Call context.Response.Write(strTemplate)
    End If
  End Sub

  Private Function GetTableHtml(ByVal Roles As String(), ByVal Users As String()) As String
    Dim xdTable As New XDocument(<table class='usersroles'><thead><tr><th>Users/roles</th><%= From r In Roles Select <th class='role'><%= r %></th> %></tr></thead></table>)

    Call xdTable.Root.Add(<tbody><%= From u In Users Select <tr><th class='user'><%= u %></th><%= From r In Roles Select <td><%= GetMarker(u, r) %></td> %></tr> %></tbody>)

    Return xdTable.ToString
  End Function

  ''' <summary>
  ''' If Membership Users are configured, those are returned. If not, users set in web.config authentication section are returned.
  ''' </summary>
  Private Function GetUsers(ByVal context As System.Web.HttpContext) As String()
    Dim strMembershipUsers() As String = GetMembershipUsers()
    If strMembershipUsers.GetUpperBound(0) >= 0 Then
      Return strMembershipUsers
    Else
      Return GetFormsAuthenticationUsers(context)
    End If
  End Function

  Private Function GetMarker(ByVal User As String, ByVal Role As String) As String
    If Security.Roles.IsUserInRole(User, Role) Then
      Return "■"
    Else
      Return " "
    End If
  End Function

  Private Function GetMembershipUsers() As String()
    Return (From u In Security.Membership.GetAllUsers.Cast(Of Security.MembershipUser)() Select u.UserName).ToArray
  End Function

  Private Function GetFormsAuthenticationUsers(ByVal context As System.Web.HttpContext) As String()
    Dim authSection = CType(context.GetSection("system.web/authentication"), Configuration.AuthenticationSection)
    Dim users As Configuration.FormsAuthenticationUserCollection = authSection.Forms.Credentials.Users

    Return (From u In users.Cast(Of Configuration.FormsAuthenticationUser)() Select u.Name).ToArray
  End Function

  ''' <summary>
  ''' This HttpHandler can also be called as an AJAX request: The querystring will/should contain parameters for adding or removing users from roles.
  ''' Parameters "add" and "to" will be present for operations to add the user to a role.
  ''' Likewise "remove" and "from" will be present to remove a user from a role.
  ''' If neither parameter sets are present, it's safe to assume it not an AJAX request.
  ''' </summary>
  ''' <param name="QueryString">Usually just context.Request.QueryString</param>
  ''' <returns>True, if querystring paramters included add/remove instructions.</returns>
  Private Function ProcessAddRemoveActions(ByVal QueryString As Specialized.NameValueCollection) As Boolean
    If QueryString("add") <> "" AndAlso QueryString("to") <> "" Then
      Call Security.Roles.AddUserToRole(QueryString("add"), QueryString("to"))
      Return True
    ElseIf QueryString("remove") <> "" AndAlso QueryString("from") <> "" Then
      Call Security.Roles.RemoveUserFromRole(QueryString("remove"), QueryString("from"))
      Return True
    Else
      Return False
    End If
  End Function
End Class
